package com.pucong.gitee.database.backup.configuration.jsonWeb;

import com.baomidou.mybatisplus.core.enums.IEnum;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.pucong.gitee.database.backup.common.selfenum.CommonEnum;
import org.postgresql.jdbc.PgArray;
import org.postgresql.util.PGobject;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;

/**
 * 配置JSON处理的一些特性：
 * 1、BigDecimal、Long、Double、Float（包括其数组类型） 转换成JSON后变为String类型，防止精度丢失。
 * 2、日期格式为： yyyy-MM-dd HH:mm:ss
 * 3、字段为空时，则不输出（null不会输出，但空字符会输出）。
 * 4、JSON转对象时，遇到未知属性，直接忽略，不报异常。
 * 5、其他参见下面的具体配置项
 *
 * @author zollty
 * @since 2017-4-20
 */
public class JacksonCustomObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = -5082708072078086407L;

    /**
     * JSON处理的相关配置
     */
    public JacksonCustomObjectMapper() {
        super();

        configToStringSerializer();

        this.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        // 转换对象为空输出空字符, 避免页面出现null
        this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                    throws IOException, JsonProcessingException {
                jsonGenerator.writeString("");
            }
        });

        // 如果为空则不输出
//        this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

        // 对于空的对象转json的时候不抛出错误
        this.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

        // 禁用遇到未知属性抛出异常
        this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);


        // 视空字符串为null
//        this.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

        // 禁用序列化日期为timestamps
//      this.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

//        // 取消对非ASCII字符的转码
//         this.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false);
//        // xxx
//        this.configure(JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS, true);
    }


    /**
     * 也可以使用注解：
     * <pre>
     *  // 1、注解处理，这里可以配置公共 baseEntity 处理
     *  @JsonSerialize(using=XXXSerializer.class)
     *  public long getId() {
     *      return id;
     *  }
     * </pre>
     */
    private void configToStringSerializer() {
        this.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, false);
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(Double.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Double.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Float.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Float.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(Long[].class, LongArraySerializer.instance);
        simpleModule.addSerializer(long[].class, LongArray2Serializer.instance);
        simpleModule.addSerializer(CommonEnum.class, EnumSerializer.instance);
        simpleModule.addSerializer(PgArray.class, PgArraySerializer.instance);
        simpleModule.addSerializer(PGobject.class, PGobjectSerializer.instance);
        simpleModule.addSerializer(IEnum.class, EnumSerializer.instance);
        this.registerModule(simpleModule);
    }

    public static final class LongArraySerializer extends StdScalarSerializer<Long[]> {
        private static final long serialVersionUID = 1L;
        static final LongArraySerializer instance = new LongArraySerializer();

        public LongArraySerializer() {
            super(Long[].class);
        }

        @Override
        public void serialize(Long[] aLong, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonGenerationException {
            if (aLong != null) {
                jsonGenerator.writeStartArray();
                for (Long val : aLong) {
                    jsonGenerator.writeString(String.valueOf(val));
                }
                jsonGenerator.writeEndArray();
            }
        }
    }

    public static final class LongArray2Serializer extends StdScalarSerializer<long[]> {
        private static final long serialVersionUID = 1L;
        static final LongArray2Serializer instance = new LongArray2Serializer();

        public LongArray2Serializer() {
            super(long[].class);
        }

        @Override
        public void serialize(long[] aLong, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonGenerationException {
            if (aLong != null) {
                jsonGenerator.writeStartArray();
                for (long val : aLong) {
                    jsonGenerator.writeString(String.valueOf(val));
                }
                jsonGenerator.writeEndArray();
            }
        }
    }


    public static final class EnumSerializer extends StdScalarSerializer<IEnum> {
        private static final long serialVersionUID = 1L;
        static final EnumSerializer instance = new EnumSerializer();

        public EnumSerializer() {
            super(IEnum.class);
        }

        @Override
        public void serialize(IEnum targetEnum, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonGenerationException {
            if (targetEnum != null) {
                jsonGenerator.writeNumber(targetEnum.getValue().toString());
            }
        }
    }

    public static final class PgArraySerializer extends StdScalarSerializer<PgArray> {
        private static final long serialVersionUID = 1L;
        static final PgArraySerializer instance = new PgArraySerializer();

        public PgArraySerializer() {
            super(PgArray.class);
        }

        @Override
        public void serialize(PgArray target, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonGenerationException {
            if (target != null) {
                jsonGenerator.writeString(target.toString());
            }
        }
    }

    public static final class PGobjectSerializer extends StdScalarSerializer<PGobject> {
        private static final long serialVersionUID = 1L;
        static final PGobjectSerializer instance = new PGobjectSerializer();

        public PGobjectSerializer() {
            super(PGobject.class);
        }

        @Override
        public void serialize(PGobject target, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonGenerationException {
            if (target != null) {
                jsonGenerator.writeString(target.getValue());
            }
        }
    }
}
